/*
The MIT License (MIT)

Copyright (c) 2013 Mike Dapiran, Brian May, Richard Pospesel, and Bert Wierenga

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software 
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#pragma once

#include <windows.h>

#include "Task.h"
//#include "TaskQueue.h"
//#include "SafeTaskQueue.h"

namespace Hogshead
{
	namespace Common
	{
 		/**
		* Parallel is a static class for doing things in parallel (like For Loops!)
		*/
		class SafeTaskQueue;
		class Parallel
		{
		public:
			
			/**
			* A parallel for loop implementation which can run a user passed function along with
			* user passed data.  The user passed function will be passed in the index it is running
			* and the  data passed in (via in_parameters).
			*
			* @param in_from The index to start from.
			* @param in_from The index to work to.
			* @param func The function to run from in_from to in_to.
			* @param in_parameters Pointer to some data func will use.
			*/
			static void forLoop(int in_from, int in_to, void (*func)(int, void*), void* in_parameters);
			/**
			* Spawns our worker threads.  Number of threads spawned is # cores - 1
			* Should be called on program initialize
			*/
			static void initialize(int in_workers = -1);

			/**
			* Releases memory, should be called on program end
			*/
			static void finalize();


			/**
			* Returns the number of physical cores this machine has.
			*/
			static int cores();

			/**
			* Returns the total number of threads (workers + main)
			*/

			static int threadCount();

			// gets the thread id number from thread's handle
			// 0 is the main thread
			static int threadID();

			static void yield();
			static void sleep(int in_millis);
		private:
			friend class TaskQueue;
			friend class TaskQueue;
			friend class SafeTaskQueue;
			static void join();
			// typedef for a function pointer to make syntax less ugly
			//typedef void (*thread_function)(void*);
			// the method each worker thread will be doing forever
			static void _run(int in_id);

			// thread masks ordered by thread id
			static LONGLONG* _thread_masks;
			// number of worker threads total we have running
			static int _worker_thread_count;
			// thread ids from 0 to MAX_THREADS-1
			static int* _thread_id;
			// number of physical cores in this machine (set during intialize)
			static int _cores;

			static volatile LONGLONG _thread_states;

			static volatile bool _finalizing;

			// method passed to worker to do for batch

			static void _for_batch(void* in_data);
			struct for_parameters
			{
				int from;
				int to;
				void (*func)(int, void*);
				void* data;
				volatile unsigned long* for_tasks_left;
			};

			static TaskQueue* _task_queue;

		};
	}
}